/*
 * SPDX-License-Identifier: BSD-2-Clause
 *
 * Copyright (C) 2017 Andes Technology Corporation
 * Rick Chen, Andes Technology Corporation <rick@andestech.com>
 * Copyright, 2024 Shandong Exponent Semiconductor CO., Ltd.            
 * Copyright, 2024 Sansec Technology CO., Ltd.                          
 *                     All Rights Reserved   
 *
 */

/* CPU specific code */
#include <common.h>
#include <cpu_func.h>
#include <irq_func.h>
#include <asm/cache.h>
#include <asm/csr.h>
#include <asm/arch-dcf/csr.h>

/*
 * cleanup_before_linux() is called just before we call linux
 * it prepares the processor for linux
 *
 * we disable interrupt and caches.
 */
int cleanup_before_linux(void)
{
	disable_interrupts();

	invalidate_icache_all();
	if(!icache_status())
		icache_enable();

	if(!dcache_status())
		dcache_enable();

	return 0;
}

void harts_early_init(void)
{
	if (CONFIG_IS_ENABLED(RISCV_MMODE)) {
        unsigned long long mcctl_val = csr_read(CSR_DCF_MCCTL);
        unsigned long long mmiscctl_val = csr_read(CSR_DCF_MMISCCTL);
        unsigned long long mhintcfg_val = csr_read(CSR_DCF_MHINTCFG);
        unsigned long long mdmcfg_val = csr_read(CSR_DCF_MIMCFG );
        unsigned long long mimcfg_val = csr_read(CSR_DCF_MDMCFG );

		mcctl_val |= (DCF_MCCTL_DC_COHEN_EN | DCF_MCCTL_CCTL_SUEN | \
							DCF_MCCTL_IC_EN | DCF_MCCTL_L1I_PREFETCH_EN | \
							DCF_MCCTL_L1D_PREFETCH_EN | DCF_MCCTL_DC_WMERGE_1_EN | \
							DCF_MCCTL_L2C_WMERGE_1_EN);

		if ((mhintcfg_val & V5_MMSC_CFG_TLB_ECC_1) || (mhintcfg_val & V5_MMSC_CFG_TLB_ECC_2))
			mcctl_val |= DCF_MCCTL_TLB_ECCEN_2;
		if ((mimcfg_val & V5_MIMCFG_IC_ECC_1) || (mimcfg_val & V5_MIMCFG_IC_ECC_2))
			mcctl_val |= DCF_MCCTL_IC_ECCEN_2;
		if ((mdmcfg_val & V5_MDMCFG_DC_ECC_1) || (mdmcfg_val & V5_MDMCFG_DC_ECC_1))
			mcctl_val |= DCF_MCCTL_DC_ECCEN_2;

		if (!CONFIG_IS_ENABLED(SYS_DCACHE_OFF))
			mcctl_val |= DCF_MCCTL_DC_EN;

		csr_write(CSR_DCF_MCCTL, mcctl_val);

		/*
         * Check DC_COHEN_EN, if cannot write to mcctl,
         * we assume this bitmap not support L2 CM
         */
        mcctl_val = csr_read(CSR_DCF_MCCTL);
        if ((mcctl_val & DCF_MCCTL_DC_COHEN_EN)) {

			/* Wait for DC_COHSTA bit be set */
			while (!(mcctl_val & DCF_MCCTL_DC_COHSTA_EN))
				mcctl_val = csr_read(CSR_DCF_MCCTL);
		}

		if (!(mmiscctl_val & DCF_MMISCCTL_NON_BLOCKING_EN))
			mmiscctl_val |= DCF_MMISCCTL_NON_BLOCKING_EN;

		csr_write(CSR_DCF_MMISCCTL, mmiscctl_val);
	}
}
